#
# Copyright (C) [2024] Xingyun Integrated Circuit, Inc.
#
# GreenCode was a private technology asset of Xingyun Integrated Circuit， Inc （Confidential）
# Author: Shawn.Tan
# Date: 2025.10.28
#
# History: Initial Version 2025.10.28
#
#
import RandomUtils

from DV.gpgpu.trees.instruction_tree import RV_G_map, RV32_G_map
from base.Sequence import Sequence
from gpgpu.EnvGPGPU import EnvGPGPU
from gpgpu.GenThreadGPGPU import GenThreadGPGPU


# This test performs some basic checks with thread locking and shared memory.
class MainSequence(Sequence):
    def generate(self, **kargs):
        shared_phys_addresses_name = "Shared PAs"
        with self.threadLockingContext():
            # One thread needs to generate the shared physical addresses
            if not self.hasSharedThreadObject(shared_phys_addresses_name):
                shared_phys_addresses = []

                for _ in range(3):
                    phys_addr = self.genPA(Size=8, Align=8, Type="D", Shared=1)
                    shared_phys_addresses.append(phys_addr)

                self.setSharedThreadObject(shared_phys_addresses_name, shared_phys_addresses)

        for _ in range(RandomUtils.random32(2, 5)):
            with self.threadLockingContext():
                shared_phys_addresses = self.getSharedThreadObject(shared_phys_addresses_name)
                self._genSharedLoadInstruction(self.choice(shared_phys_addresses))
                self._genRandomInstructions()

    # Generate a load instruction to a shared address and assert that the
    # destination register is marked unpredictable.
    #
    #  @param aSharedPhysAddr A shared physical address to target with the
    #  load instruction.
    def _genSharedLoadInstruction(self, aSharedPhysAddr):
        target_addr = self.genVAforPA(Size=8, Align=8, Type="D", PA=aSharedPhysAddr)
        if self.getGlobalState("AppRegisterWidth") == 32:
            instr = "LW##CALM"
        else:
            instr = "LD##CALM"
        instr_id = self.genInstruction(instr, {"LSTarget": target_addr})

        instr_record = self.queryInstructionRecord(instr_id)
        dest_reg_index = instr_record["Dests"]["rd"]
        dest_reg_name = "x%d" % dest_reg_index
        if (dest_reg_index != 0) and (
            not self.isRegisterReserved(dest_reg_name, access="Read", resv_type="Unpredictable")
        ):
            self.error("Destination register %s was not marked as unpredictable" % dest_reg_name)

    # Generate a random number of a wide variety of instructions.
    def _genRandomInstructions(self):
        for _ in range(RandomUtils.random32(0, 10)):
            if self.getGlobalState("AppRegisterWidth") == 32:
                instr = RV32_G_map.pick(self.genThread)
            else:
                instr = RV_G_map.pick(self.genThread)
            self.genInstruction(instr)


MainSequenceClass = MainSequence
GenThreadClass = GenThreadGPGPU
EnvClass = EnvGPGPU
